﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PSL.ST
{
    /// <summary>
    /// Association of an token in the value-parser
    /// </summary>
    public enum OperatorAssociation
    {
        None = 0,
        Left = 1,
        Right = 2
    }

    /// <summary>
    /// Type of operators
    /// </summary>
    public enum OperatorType
    {
        Add = 0,
        Sub = 1,
        Mul = 2,
        Div = 3,
        Pow = 4
    }

    internal class OperatorNode : TreeNode
    {
        #region Private Member
        private OperatorType type;
        private OperatorAssociation association;
        private int precedence;
        #endregion

        #region Constructor
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="Parent"></param>
        public OperatorNode(TreeNode Parent)
            : base(Parent, TreeNodeType.Operator)
        {

        }
        #endregion

        public override TreeNode CloneNode()
        {
            OperatorNode returnNode = new OperatorNode(null);

            returnNode.OperatorType = this.OperatorType;
            returnNode.Association = this.Association;

            return returnNode;
        }

        public override dynamic Execute(PSLEngine Engine)
        {
            dynamic returnValue = null;

            dynamic left = Children[1].Execute(Engine);
            dynamic right = Children[0].Execute(Engine);

            switch (this.OperatorType)
            {
                case OperatorType.Pow:
                    returnValue = Math.Pow(left, right);
                    break;
                case OperatorType.Mul:
                    returnValue = left * right;
                    break;
                case OperatorType.Div:
                    returnValue = left / right;
                    break;
                case OperatorType.Add:
                    returnValue = left + right;
                    break;
                case OperatorType.Sub:
                    returnValue = left - right;
                    break;
            }

            return returnValue;
        }

        #region Public Member
        /// <summary>
        /// Precedence
        /// </summary>
        public int Precedence
        {
            get { return precedence; }
            set { precedence = value; }
        }

        /// <summary>
        /// Get and set the type of the operator, automatically set the precedence
        /// </summary>
        public OperatorType OperatorType
        {
            get
            {
                return type;
            }
            set
            {
                type = value;

                switch (value)
                {
                    case OperatorType.Pow:
                        precedence = 4;
                        break;
                    case OperatorType.Mul:
                        precedence = 3;
                        break;
                    case OperatorType.Div:
                        precedence = 3;
                        break;
                    case OperatorType.Add:
                        precedence = 2;
                        break;
                    case OperatorType.Sub:
                        precedence = 2;
                        break;
                }
            }
        }

        /// <summary>
        /// Operator association
        /// </summary>
        public OperatorAssociation Association
        {
            get { return association; }
            set { association = value; }
        }
        #endregion
    }
}
